package com.gh.lucene.util.mapping;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;

import com.gh.lucene.util.UserData;

/**
 * 通过TypeField 完成解析工作
 * 
 * @author bastengao
 * 
 */

public class TypeFieldResolver implements Resolver {
	@SuppressWarnings("unchecked")
	private Map<Class, Mapper> classMappers;
	@SuppressWarnings("unchecked")
	private Map<Type, Mapper> typeMappers;
	private Map<String, Type> types;
	private Map<String, String> names;

	@SuppressWarnings("unchecked")
	public TypeFieldResolver() {
		classMappers = new HashMap<Class, Mapper>();
		typeMappers = new HashMap<Type, Mapper>();
		types = new HashMap<String, Type>();
		names = new HashMap<String, String>();
	}

	public <E extends UserData> void bindMapper(Mapper<E> mapper,
			Class<E> clazz, Type type) {
		classMappers.put(clazz, mapper);
		typeMappers.put(type, mapper);
		types.put(type.getFieldName() + type.getValue(), type);
		names.put(type.getFieldName(), type.getFieldName() + type.getValue());
	}

	@Override
	@SuppressWarnings("unchecked")
	public <E extends UserData> Mapper<E> getMapper(E o) {
		return classMappers.get(o.getClass());
	}

	@Override
	@SuppressWarnings("unchecked")
	public Mapper getMapper(Document document) {
		return find(document);
	}

	@SuppressWarnings("unchecked")
	private Mapper find(Document document) {
		Set<String> fieldNames = names.keySet();
		for (String name : fieldNames) {
			Field field = document.getField(name);
			if (field != null) {
				String value = field.stringValue();
				if (value != null) {
					Type type = types.get(name + value);
					if (type != null) {
						Mapper mapper = typeMappers.get(type);
						if (mapper != null) {
							return mapper;
						}
					}
				}
			}
		}
		return null;
	}

	/**
	 * 唯一标识一下Document
	 * 
	 * @author bastengao
	 * 
	 */
	public static class Type {
		private String fieldName;
		private String value;

		public Type(String fieldName, String value) {
			super();
			this.fieldName = fieldName;
			this.value = value;
		}

		public String getFieldName() {
			return fieldName;
		}

		public String getValue() {
			return value;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result
					+ ((fieldName == null) ? 0 : fieldName.hashCode());
			result = prime * result + ((value == null) ? 0 : value.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Type other = (Type) obj;
			if (fieldName == null) {
				if (other.fieldName != null)
					return false;
			} else if (!fieldName.equals(other.fieldName))
				return false;
			if (value == null) {
				if (other.value != null)
					return false;
			} else if (!value.equals(other.value))
				return false;
			return true;
		}

	}
}
